package org.ccay.core.encrypt.impl;

import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.inject.Inject;
import javax.inject.Named;

import org.apache.commons.codec.binary.Base64;
import org.ccay.core.encrypt.DecryptionException;
import org.ccay.core.encrypt.EncryptionException;
import org.ccay.core.encrypt.IDecryption;
import org.ccay.core.encrypt.IEncryption;
import org.ccay.core.util.EncodingUtil;

/**
 * AES 加密和解密算法的实现
 * 
 * @author chaowangbang
 * @since 2011-11-1
 */
@Named("aes")
public class Aes implements IEncryption, IDecryption {
 
	private static final int DEFAULT_KEY_SIZE = 128;
	private static final String AES_NAME = "AES";
	private static final String EX_UNABLE_ENCRYPT = "ccay.core.00050001";
	private static final String EX_UNABLE_DECRYPT = "ccay.core.00050002";
	private static final String EX_NO_ALGORITHM = "ccay.core.00050004";

	@Inject
	private EncryptConfigBean defaultEncryptConfig;

	/*
	 * （非 Javadoc）
	 * 
	 * @see
	 * org.ccay.core.encrypt.IDecryption#decrypt(java.lang.String,
	 * java.lang.String)
	 */
	public String decrypt(String encryptedString, String key) {
		try {
			SecretKeySpec skeySpec = new SecretKeySpec(
					Base64.decodeBase64(key), AES_NAME);
			Cipher cipher = Cipher.getInstance(AES_NAME);
			cipher.init(Cipher.DECRYPT_MODE, skeySpec);

			byte[] encrypted = cipher.doFinal(Base64
					.decodeBase64(encryptedString));

			return new String(encrypted,EncodingUtil.UTF_8);
		} catch (NoSuchAlgorithmException e) {
			throw new DecryptionException(EX_NO_ALGORITHM, e);
		} catch (GeneralSecurityException e) {
			throw new DecryptionException(EX_UNABLE_DECRYPT, e);
		} catch (UnsupportedEncodingException e) {
			throw new DecryptionException(EX_UNABLE_DECRYPT, e);
		}
	}

	/*
	 * （非 Javadoc）
	 * 
	 * @see
	 * org.ccay.core.encrypt.IDecryption#decrypt(java.lang.String)
	 */
	public String decrypt(String encryptedString) {
		return decrypt(encryptedString, defaultEncryptConfig.getDefaultKey());
	}

	/*
	 * （非 Javadoc）
	 * 
	 * @see
	 * org.ccay.core.encrypt.IEncryption#encrypt(java.lang.String,
	 * java.lang.String)
	 */
	public String encrypt(String originalString, String key) {
		try {
			SecretKeySpec skeySpec = new SecretKeySpec(
					Base64.decodeBase64(key), AES_NAME);
			Cipher cipher = Cipher.getInstance(AES_NAME);
			cipher.init(Cipher.ENCRYPT_MODE, skeySpec);

			byte[] encrypted = cipher.doFinal(originalString.getBytes(EncodingUtil.UTF_8));

			return Base64.encodeBase64String(encrypted);
		} catch (NoSuchAlgorithmException e) {
			throw new EncryptionException(EX_NO_ALGORITHM, e);
		} catch (GeneralSecurityException e) {
			throw new EncryptionException(EX_UNABLE_ENCRYPT, e);
		} catch (UnsupportedEncodingException e) {
			throw new EncryptionException(EX_UNABLE_ENCRYPT, e);
		}
	}

	/*
	 * （非 Javadoc）
	 * 
	 * @see
	 * org.ccay.core.encrypt.IEncryption#encrypt(java.lang.String)
	 */
	public String encrypt(String originalString) {

		return encrypt(originalString, defaultEncryptConfig.getDefaultKey());
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.ccay.core.encrypt.IEncryption#generationRandomKey()
	 */
	public String generationRandomKey() {
		return generationRandomKey(DEFAULT_KEY_SIZE);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.ccay.core.encrypt.IEncryption#generationRandomKey(int)
	 */
	public String generationRandomKey(int length) {
		KeyGenerator kgen;
		try {
			kgen = KeyGenerator.getInstance(AES_NAME);
			kgen.init(length);
			SecretKey skey = kgen.generateKey();
			byte[] raw = skey.getEncoded();
			return Base64.encodeBase64String(raw);
		} catch (NoSuchAlgorithmException e) {
			throw new EncryptionException(EX_NO_ALGORITHM, e);
		}
	}
}
